#ifndef __TINY_TEST__

#include "vbb_STORAGE.h"
#include <string.h>
#include "vbb_flashmem.h"
#include <stdlib.h>
#include "vbb_Header.h"
#include "vbb_FirmwareUtils.h"

#define STORAGE_ADDR_CONFIG     16711680
#define STORAGE_MAX_CONFIG      256
#define STORAGE_PAGE_SIZE       256

extern VBB_FlashMem flashMem;
VBB_Storage storage;

void STORAGE_DefaultConfig(VBB_Config * Config)
{
    strcpy(Config->OwnerId, "SOMECORP");
    strcpy(Config->VehicleId, "VEHICLE0");
    strcpy(Config->PlateNumber, "29A00000");
    Config->MessagePerHour_Move = 360;
    Config->MessagePerHour_Idle = 10;   
    Config->ServerMessagePerHour = 60;
    strcpy(Config->HTTPServerAddr, "115.84.179.74");
    strcpy(Config->HTTPServerPort, "7979");
    strcpy(Config->HTTPServerAddr2, "115.84.179.74");
    strcpy(Config->HTTPServerPort2, "7878");
    Config->PulseOnKm = 2540;
    Config->ActiveOnHigh_AC = 0;
    Config->ActiveOnHigh_Door = 0;
    Config->ActiveOnHigh_Engine = 0;  
    Config->OfflineMode = 0; // Dong: for test
    Config->WarningVelocity = 80;
    strcpy(Config->FirmwareDir, "fw_ufw");
    strcpy(Config->FirmwarePrefix, "bufw");
    strcpy(Config->DriverName, "LAI XE A");
    strcpy(Config->VIN, "0123456789ABCDEFG");
    Config->HTTP_ProtocolEnable = 1;
}

char _line[512];

extern void SPANSION_Band0_Select(void);
extern void SPANSION_Band0_Deselect(void);
extern void SPANSION_Band1_Select(void);
extern void SPANSION_Band1_Deselect(void);

extern void SD_Select(void);
extern void SD_Deselect(void);

void vbb_STORAGE_Init(void)
{    
    STORAGE_DefaultConfig(&(storage.config));                   
    
    /*
    storage.flash.numOfPages = flashMem.flash.numOfPages;
    storage.flash.pageSize = flashMem.flash.pageSize;
    
    if (vbb_DeviceModel() == CNS03)
        vbb_PIN_Init(&(storage.flash.select_pin), GPIOE, 13, PIN_MODE_GENERAL_OUTPUT_PUSH_PULL);
    else if (vbb_DeviceModel() == CNS01)
        vbb_PIN_Init(&(storage.flash.select_pin), GPIOB, 1, PIN_MODE_GENERAL_OUTPUT_PUSH_PULL);
    else if (vbb_DeviceModel() == BA01)
        vbb_PIN_Init(&(storage.flash.select_pin), GPIOB, 1, PIN_MODE_GENERAL_OUTPUT_PUSH_PULL);

    storage.flash.spi.pin_clk = flashMem.flash.spi.pin_clk;    
    storage.flash.spi.pin_miso = flashMem.flash.spi.pin_miso;
    storage.flash.spi.pin_mosi = flashMem.flash.spi.pin_mosi;
    storage.flash.spi.SPIx = flashMem.flash.spi.SPIx;    
    */
    
    if (vbb_DeviceModel() == CNS03)
        vbb_Flash_Init(&(storage.flash), 256, 65536, SPI3, GPIOE, 12);
    else if (vbb_DeviceModel() == CNS01 || vbb_DeviceModel() == BA01)
        vbb_Flash_Init(&(storage.flash), 256, 65536, SPI3, GPIOB, 0);
    
    /*
    vbb_OUTPUT_Print("INFO: SPANSION band 1 information: ");
    vbb_OUTPUT_PrintNumberUnSigned(vbb_Flash_ReadId(&(storage.flash)));
    vbb_OUTPUT_Print(" ");
    vbb_OUTPUT_PrintNumberUnSigned(vbb_Flash_ReadElectronicSignature(&(storage.flash)));
    vbb_OUTPUT_Print("\r\n");
    */
    
    /*vbb_CONSOLE_Printf("INFO: SPANSION die 1 information: %2xh %2xh.\r\n", vbb_Flash_ReadId(&(storage.flash)), vbb_Flash_ReadElectronicSignature(&(storage.flash)));*/
    
    /*vbb_Flash_UnlockFlash(&(storage.flash));*/
    
    vbb_STORAGE_ReadConfig();  
}

char _tmpStr[128];

void STORAGE_GetString(const char * Line, char * Str)
{
    char * tmp = Str;
    while ((Line[0] >= 'a' && Line[0] <= 'z') || (Line[0] >= 'A' && Line[0] <= 'Z') || (Line[0] >= '0' && Line[0] <= '9') || (Line[0] == '-') || (Line[0] == '.'))
    {
        tmp[0] = Line[0];
        tmp++;
        Line++;
    }
    tmp[0] = 0;
}

bool vbb_STORAGE_CheckConfig(const char * ConfigLine)
{
    return strstr(ConfigLine, "CK+CONFIG,") != NULL;
}

void vbb_STORAGE_ReadConfig(void)
{
    unsigned int Addr = STORAGE_ADDR_CONFIG;
    char * ln;
    int count = 0;
    
    vbb_OUTPUT_Print("INFO: Read configuration.\r\n");
    
    vbb_Flash_PageRead(&(storage.flash), Addr);
    vbb_StrCpy(_line, storage.flash.tmpPage, 256);
    
    if (_line[0] != (char)0xFF && _line[0] != 'C')
    {
        vbb_OUTPUT_Print("INFO: Format configuration storage ");
        vbb_STORAGE_Clear();
        vbb_OUTPUT_Print("[DONE]\r\n");
    }
    
    while (_line[0] == 'C' && _line[1] == 'K' && count < STORAGE_MAX_CONFIG)
    {
        ln = vbb_FindStr(_line, "CK+CONFIG,");
        if (ln)
        {
            if ((ln = vbb_FindStr(_line, "ownerid,")) != 0)
            {                
                ln += vbb_GetLen("ownerid,");                                
                STORAGE_GetString(ln, storage.config.OwnerId);
            }             
            else if ((ln = vbb_FindStr(_line, "vehicleid,")) != 0)
            {
                ln += vbb_GetLen("vehicleid,");
                STORAGE_GetString(ln, storage.config.VehicleId);
            }
            else if ((ln = vbb_FindStr(_line, "plate,")) != 0)
            {
                ln += vbb_GetLen("plate,");
                STORAGE_GetString(ln, storage.config.PlateNumber);
                
                vbb_CONSOLE_Printf("INFO: Config plate %s.\r\n", storage.config.PlateNumber);
            }
            else if ((ln = vbb_FindStr(_line, "fwdir,")) != 0)
            {
                ln += vbb_GetLen("fwdir,");
                STORAGE_GetString(ln, storage.config.FirmwareDir);
            }
            else if ((ln = vbb_FindStr(_line, "fwprefix,")) != 0)
            {
                ln += vbb_GetLen("fwprefix,");
                STORAGE_GetString(ln, storage.config.FirmwarePrefix);
            }            
            else if ((ln = vbb_FindStr(_line, "vin,")) != 0)
            {
                ln += vbb_GetLen("vin,");
                STORAGE_GetString(ln, storage.config.VIN);
            }
            else if ((ln = vbb_FindStr(_line, "driver,")) != 0)
            {
                ln += vbb_GetLen("driver,");
                STORAGE_GetString(ln, storage.config.DriverName);
            }
            else if ((ln = vbb_FindStr(_line, "http,")) != 0)
            {
                ln += vbb_GetLen("http,");
                STORAGE_GetString(ln, storage.config.HTTPServerAddr);
                ln += vbb_GetLen(storage.config.HTTPServerAddr);
                if (ln[0] == ',')
                    STORAGE_GetString(ln + 1, storage.config.HTTPServerPort);
            }
            else if ((ln = vbb_FindStr(_line, "http2,")) != 0)
            {
                ln += vbb_GetLen("http2,");
                STORAGE_GetString(ln, storage.config.HTTPServerAddr2);
                ln += vbb_GetLen(storage.config.HTTPServerAddr2);
                if (ln[0] == ',')
                    STORAGE_GetString(ln + 1, storage.config.HTTPServerPort2);
            }
            else if ((ln = vbb_FindStr(_line, "msgperhour_move,")) != 0)
            {
                ln += vbb_GetLen("msgperhour_move,");
                STORAGE_GetString(ln, _tmpStr);
                storage.config.MessagePerHour_Move = atoi(_tmpStr);
            }
            else if ((ln = vbb_FindStr(_line, "msgperhour_idle,")) != 0)
            {
                ln += vbb_GetLen("msgperhour_idle,");                
                STORAGE_GetString(ln, _tmpStr);
                storage.config.MessagePerHour_Idle = atoi(_tmpStr);
            }
            else if ((ln = vbb_FindStr(_line, "pulseonkm,")) != 0)
            {
                ln += vbb_GetLen("pulseonkm,");
                STORAGE_GetString(ln, _tmpStr);
                storage.config.PulseOnKm = atoi(_tmpStr);
            }
            else if ((ln = vbb_FindStr(_line, "warningvel,")) != 0)
            {
                ln += vbb_GetLen("warningvel,");
                STORAGE_GetString(ln, _tmpStr);
                storage.config.WarningVelocity = atoi(_tmpStr);
            }
            else if ((ln = vbb_FindStr(_line, "active_door,")) != 0)
            {
                ln += vbb_GetLen("active_door,");
                STORAGE_GetString(ln, _tmpStr);
                storage.config.ActiveOnHigh_Door = atoi(_tmpStr);
            }
            else if ((ln = vbb_FindStr(_line, "active_engine,")) != 0)
            {
                ln += vbb_GetLen("active_engine,");
                STORAGE_GetString(ln, _tmpStr);
                storage.config.ActiveOnHigh_Engine = atoi(_tmpStr);
            }
            else if ((ln = vbb_FindStr(_line, "active_ac,")) != 0)
            {
                ln += vbb_GetLen("active_ac,");
                STORAGE_GetString(ln, _tmpStr);
                storage.config.ActiveOnHigh_AC = atoi(_tmpStr);
            }
            else if ((ln = vbb_FindStr(_line, "offline,")) != 0)
            {
                ln += vbb_GetLen("offline,");
                STORAGE_GetString(ln, _tmpStr);
                storage.config.OfflineMode = atoi(_tmpStr);
            }
            else if ((ln = vbb_FindStr(_line, "push,")) != 0)
            {
                ln += vbb_GetLen("push,");
                STORAGE_GetString(ln, _tmpStr);
                storage.config.ServerMessagePerHour = atoi(_tmpStr);
            }
            else if ((ln = vbb_FindStr(_line, "http_protocol,")) != 0)
            {
                ln += vbb_GetLen("http_protocol,");
                STORAGE_GetString(ln, _tmpStr);
                storage.config.HTTP_ProtocolEnable = atoi(_tmpStr);
            }
            
            Addr += STORAGE_PAGE_SIZE;
            vbb_Flash_PageRead(&(storage.flash), Addr);
            vbb_StrCpy(_line, storage.flash.tmpPage, STORAGE_PAGE_SIZE);
            
            count++;
        }
        else
            break;
    }        
    
    vbb_CONSOLE_Printf("CONFIG: ownerid,%s\r\n", storage.config.OwnerId);
    vbb_CONSOLE_Printf("CONFIG: vehicleid,%s\r\n", storage.config.VehicleId);
    vbb_CONSOLE_Printf("CONFIG: plate,%s\r\n", storage.config.PlateNumber);
    vbb_CONSOLE_Printf("CONFIG: msgperhour_move,%d\r\n", storage.config.MessagePerHour_Move);
    vbb_CONSOLE_Printf("CONFIG: msgperhour_idle,%d\r\n", storage.config.MessagePerHour_Idle);
    vbb_CONSOLE_Printf("CONFIG: http,%s:%s\r\n", storage.config.HTTPServerAddr, storage.config.HTTPServerPort);
    vbb_CONSOLE_Printf("CONFIG: http2,%s:%s\r\n", storage.config.HTTPServerAddr2, storage.config.HTTPServerPort2);
    vbb_CONSOLE_Printf("CONFIG: pulseonkm,%d\r\n", storage.config.PulseOnKm);
    vbb_CONSOLE_Printf("CONFIG: active_door,%d\r\n", storage.config.ActiveOnHigh_Door);
    vbb_CONSOLE_Printf("CONFIG: active_engine,%d\r\n", storage.config.ActiveOnHigh_Engine);
    vbb_CONSOLE_Printf("CONFIG: active_ac,%d\r\n", storage.config.ActiveOnHigh_AC);    
    vbb_CONSOLE_Printf("CONFIG: offline,%d\r\n", storage.config.OfflineMode);
    vbb_CONSOLE_Printf("CONFIG: fwdir,%s\r\n", storage.config.FirmwareDir);
    vbb_CONSOLE_Printf("CONFIG: fwprefix,%s\r\n", storage.config.FirmwarePrefix);
    vbb_CONSOLE_Printf("CONFIG: driver,%s\r\n", storage.config.DriverName);
    vbb_CONSOLE_Printf("CONFIG: vin,%s\r\n", storage.config.VIN);
    vbb_CONSOLE_Printf("CONFIG: warningvel,%d\r\n", storage.config.WarningVelocity);
    vbb_CONSOLE_Printf("CONFIG: push,%d\r\n", storage.config.ServerMessagePerHour);
    vbb_CONSOLE_Printf("CONFIG: http_protocol,%d\r\n", storage.config.HTTP_ProtocolEnable);
}

extern unsigned int FLASHMEM_GetSectorSize(unsigned int Address);

void vbb_STORAGE_AddConfig(const char * ConfigLine)
{
    unsigned int Addr = STORAGE_ADDR_CONFIG;    
    int count = 0;
    
    vbb_OUTPUT_Print("INFO: Add config \"");
    vbb_OUTPUT_PrintDebug(ConfigLine);
    vbb_OUTPUT_Print("\"");
    
    vbb_Flash_PageRead(&(storage.flash), Addr);
    vbb_StrCpy(_line, storage.flash.tmpPage, STORAGE_PAGE_SIZE);
    
    while (_line[0] == 'C' && _line[1] == 'K' && count < STORAGE_MAX_CONFIG)
    {                     
        vbb_OUTPUT_PrintDebug(_line);
        vbb_OUTPUT_Print("\r\n");        
        Addr += STORAGE_PAGE_SIZE;
        vbb_Flash_PageRead(&(storage.flash), Addr);
        vbb_StrCpy(_line, storage.flash.tmpPage, STORAGE_PAGE_SIZE);  
        count++;
    }
    
    if (count < 256)
    {
        if (Addr % FLASHMEM_GetSectorSize(Addr) == 0)    
        {
            vbb_CONSOLE_Printf("(erase sector 0x%x)", Addr);
            vbb_Flash_EraseSector(&(storage.flash), Addr);
        }
        
        vbb_StrCpy(storage.flash.tmpPage, ConfigLine, STORAGE_PAGE_SIZE);
        vbb_Flash_PageProgram(&(storage.flash), Addr);
        
        vbb_OUTPUT_Print("[DONE]\r\n");
    }
    else
    {
        vbb_OUTPUT_Print("[FAIL]\r\n");
    }
}

void vbb_STORAGE_Clear(void)
{
    vbb_Flash_EraseSector(&(storage.flash), STORAGE_ADDR_CONFIG);    
}

#endif
